﻿namespace express.bttree;

public abstract class OpNode : Node
{
    public String Method { get; set; }

    public List<Object> Params { get; set; }

    public Object Value { get; set; }

    public Operator Op { get; set; }

    public OpNode()
    {

    }

    private void printLog(String methodName, Object result, Boolean ok)
    {
        String logText = "exp=" + methodName + "(" + this.Params + ") " + this.Op + " " + this.Value + ";";
        logText += "result=" + result + ";";
        logText += "ok=" + ok + ";";
        Console.WriteLine(logText);
    }

    protected abstract Dictionary<String, Command> GetCommands();

    public override State execute(Context context)
    {
        if (this.Method == null || this.Value == null || this.Op == Operator.nil)
        {
            throw new Exception("必要参数未设置，请检查");
        }

        var commands = GetCommands();
        if (!commands.ContainsKey(this.Method))
        {
            throw new Exception("不存在的函数，method:" + this.Method);
        }
        Command command = commands[this.Method];
        if (command == null)
        {
            throw new Exception(this.Method + " 未定义");
        }
        Object result = command(context, new ParamList(this.Params));
        context.AddResult(result);

        if (!Utils.comparable(result, this.Value))
        {
            throw new Exception("表达式 " + this.Method + " 不可比较，result:" + result + ",value:" + this.Value);
        }
        if (result is Boolean)
        {
            Boolean ok = (Boolean)result == Convert.ToBoolean(this.Value);
            printLog(this.Method, result, ok);
            if (ok)
            {
                return State.True;
            }
            else
            {
                return State.False;
            }
        }
        else if (result is Int32 || result is Int64)
        {
            long exp1 = Convert.ToInt64(result);
            long exp2 = Convert.ToInt64(this.Value);
            Boolean ok;
            switch (this.Op)
            {
                case Operator.eq:
                    ok = exp1 == exp2;
                    break;
                case Operator.gt:
                    ok = exp1 > exp2;
                    break;
                case Operator.gte:
                    ok = exp1 >= exp2;
                    break;
                case Operator.lt:
                    ok = exp1 < exp2;
                    break;
                case Operator.lte:
                    ok = exp1 <= exp2;
                    break;
                case Operator.ne:
                    ok = exp1 != exp2;
                    break;
                default:
                    throw new Exception("运算符不存在");
            }
            printLog(this.Method, result, ok);
            if (ok)
            {
                return State.True;
            }
            else
            {
                return State.False;
            }
        }
        else if (result is String)
        {
            if (result == null)
            {
                return State.Break;
            }
            String exp1 = result.ToString();
            String exp2 = this.Value.ToString();
            Boolean ok;
            switch (this.Op)
            {
                case Operator.eq:
                    ok = string.Equals(exp1, exp2);
                    break;
                case Operator.ne:
                    ok = !string.Equals(exp1, exp2);
                    break;
                default:
                    throw new Exception("字符串不支持该运算符，op:" + this.Op);

            }
            if (ok)
            {
                return State.True;
            }
            else
            {
                return State.False;
            }
        }
        else
        {
            throw new Exception("该类型不支持，result:" + result);
        }
    }
}